#! /usr/bin/env python
#coding=utf-8

import sys
import os
import sqlite3
sys.path.append('../')
from parameter.user_group_parser import GroupFileParser
from parameter.user_group_parser import PasswdFileParser
from tablebuilder import TableBuilder

class ParameterTableBuilder(TableBuilder):
    def __init__(self, cursor):
        TableBuilder.__init__(self, cursor, "parameters")

    def getColumns(self):
        return ("prefix STRING PRIMARY KEY", "type STRING",
            "dacUser STRING ", "dacGroup STRING ", "dacMode INTEGER DEFAULT(0)",
            "selinuxLabel STRING", "value STRING", "fileId INTEGER")

    def getKeys(self):
        return ("prefix", "type", "dacUser", "dacGroup", "dacMode", "selinuxLabel", "value", "fileId")

class ParameterParser(dict):
    def __init__(self, prefix, parameter=None):
        self["prefix"] = prefix
        if parameter == None:
            self["type"] = "string"
            self["dacUser"] = ""
            self["dacGroup"] = ""
            self["dacMode"] = 0
            self["selinuxLabel"] = ""
            self["value"] = ""
            self["fileId"] = -1
        else:
            self["type"] = parameter.get("type")
            self["dacUser"] = parameter.get("dacUser")
            self["dacGroup"] = parameter.get("dacGroup")
            self["dacMode"] = parameter.get("dacMode")
            self["selinuxLabel"] = parameter.get("selinuxLabel")
            self["value"] = parameter.get("value")
            self["fileId"] = parameter.get("fileId")

    def decode(self, info):
        self["value"] = info.strip("\"").strip("\'")
        #print("value '%s'" % self["value"])
        return True

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return "%s= DAC[%s:%s:%o] selinux[%s] value=%s" % (self["prefix"],
            self["dacUser"], self["dacGroup"], self["dacMode"],
            self["selinuxLabel"], self["value"])

class ParameterDacParser(ParameterParser):
    def __init__(self, prefix, parameter=None):
        ParameterParser.__init__(self, prefix, parameter)

    def decode(self, info):
        dacInfo = info.strip("\"").strip("\'").split(":")
        if len(dacInfo) < 3:
            print("Invalid dac %s" % info)
            return False

        self["dacUser"] = dacInfo[0]
        self["dacGroup"] = dacInfo[1]
        self["dacMode"] = dacInfo[2]
        if len(dacInfo) > 3:
            self["type"] = dacInfo[3]
        return True

class ParameterSelinuxParser(ParameterParser):
    def __init__(self, prefix, parameter=None):
        ParameterParser.__init__(self, prefix, parameter)

    def decode(self, info):
        self["selinuxLabel"] = info
        #print("name %s selinux %s" % (self["prefix"], info))
        return True

class ParameterFileParser():
    def __init__(self, files):
        self._parameters = {}
        self._files = files

    def _handleParamInfo(self, fileName, paramInfo):
        paramName = paramInfo[0].strip()
        oldParam = self._parameters.get(paramName)
        if fileName.endswith(".para.dac") :
            param = ParameterDacParser(paramName, oldParam)
            if (param.decode(paramInfo[2].strip())) :
                self._parameters[paramName] = param
                # only for dac
                param["fileId"] = self.getFileId(fileName)
        elif fileName.endswith(".para") :
            param = ParameterParser(paramName, oldParam)
            if (param.decode(paramInfo[2].strip())) :
                self._parameters[paramName] = param
        else:
            param = ParameterSelinuxParser(paramName, oldParam)
            if (param.decode(paramInfo[2].strip())) :
                self._parameters[paramName] = param

    def loadParameterFile(self, fileName, str = "="):
        if fileName is None :
            return
        print(" loadParameterFile %s" % fileName)
        with open(fileName, encoding='utf-8') as fp:
            line = fp.readline()
            while line :
                #print("line %s" % (line))
                if line.startswith("#") or len(line) < 3:
                    line = fp.readline()
                    continue
                paramInfo = line.partition(str)
                if len (paramInfo) != 3:
                    line = fp.readline()
                    continue
                self._handleParamInfo(fileName, paramInfo)
                line = fp.readline()

    def dumpParameter(self):
        for param in self._parameters.values() :
            print(str(param))

    def _saveParameter(self, cursor):
        builder = ParameterTableBuilder(cursor)
        builder.createTable()
        cnt = 0
        script = "BEGIN TRANSACTION;\n"
        for item in self._parameters.values():
            sqlcmd = builder.addObjectToDb(item, False, True)
            #print(sqlcmd)
            script = script + sqlcmd + ";\n"
            cnt = cnt + 1
        script = script + "COMMIT;\n"
        cursor = builder.getCursor()
        cursor.executescript(script)

    def saveParameter(self, path):
        conn = sqlite3.connect(path)
        cursor = conn.cursor()
        self._saveParameter(cursor)
        conn.commit()
        cursor.close()
        conn.close()

    def _checkFile(self, file):
        valid_file_ext = [".para", ".para.dac"]
        if not file.is_file():
            return False
        for ext in valid_file_ext:
            if file.name.endswith(ext):
                return True
        return False

    def _scanParameterFile(self, dir):
        if not os.path.exists(dir):
            return
        with os.scandir(dir) as files:
            for file in files:
                if self._checkFile(file):
                    self.loadParameterFile(file.path)

    def scanParameterFile(self, dir):
        parameter_paths = [
            "/system/etc/param/ohos_const",
            "/vendor/etc/param",
            "/chip_prod/etc/param",
            "/sys_prod/etc/param",
            "/system/etc/param",
        ]
        for path in parameter_paths:
            self._scanParameterFile(dir + "/packages/phone" + path)

    def getFileId(self, fileName) :
        parameter_paths = [
            "/system/etc/param/ohos_const",
            "/vendor/etc/param",
            "/chip_prod/etc/param",
            "/sys_prod/etc/param",
            "/system/etc/param",
        ]
        for path in parameter_paths:
            index = fileName.find(path)
            if (index < 0) :
                continue
            name = fileName[index :]
            if self._files and self._files.get(name):
                return self._files.get(name).get("fileId")
            break
        return -1

def _create_arg_parser():
    import argparse
    parser = argparse.ArgumentParser(description='Collect parameter information from xxxx/etc/param dir.')
    parser.add_argument('-i', '--input',
                        help='input parameter files base directory example "out/rk3568/packages/phone/" ',
                        action='append', required=True)
    parser.add_argument('-o', '--output',
                        help='output parameter information database directory', required=True)
    parser.add_argument('-P', '--parameter',
                        help='input parameter from board by exec param get ', required=False)
    return parser

def Collect(options, files):
    input = os.path.realpath(options.input)
    output = os.path.realpath(options.output)
    if not os.path.exists(output) or not os.path.exists(input):
        print("Failed to collect parameter info input %s output %s" % (input, output))
        return

    parser = ParameterFileParser(files)
    parser.scanParameterFile(input)
    parser.loadParameterFile(input + "/packages/phone/system/etc/selinux/targeted/contexts/parameter_contexts", " ")

    if options.__contains__('parameter') and options.parameter :
        parser.loadParameterFile(os.path.realpath(options.parameter), "=")

    #parser.dumpParameter()
    parser.saveParameter(output + "/archinfo.db")

    group = GroupFileParser()
    group.loadFile(input + "/packages/phone/system/etc/group")

    #parser.dump()
    group.save(output + "/archinfo.db")

    passwd = PasswdFileParser()
    passwd.loadFile(input + "/packages/phone/system/etc/passwd")
    passwd.dump()
    passwd.save(output + "/archinfo.db")

if __name__ == '__main__':
    args_parser = _create_arg_parser()
    options = args_parser.parse_args()
    Collect(options, None)
